﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Data.Common;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace MSharp.Data
{
    public class TypeInfo<T>
    {
        static TypeInfo()
        {
            TyThis = typeof(T);

            Name = TyThis.Name;

            IsValueType = TyThis.IsValueType;

            IsAnonymousType = Name.Contains("AnonymousType");

            if (Name == "DbParameter[]" || Name == "IDbParameter[]")
            {
                IsArrayParameter = true;
            }
            else if (Name == "List`1")
            {
                Type typeTmp = TyThis.GetGenericArguments()[0];
                if (typeTmp.Name == "DbParameter" || typeTmp.Name == "IDbParameter")
                {
                    IsListParameter = true;
                }
            }
            //else if (IsAnonymousType)
            //{
            //    Props = TyThis.GetProperties();
            //    PropNames = new List<string>();
            //    PropMapping = new Dictionary<string, PropertyInfo>();
            //    foreach (var prop in Props)
            //    {
            //        PropMapping.Add(prop.Name, prop);
            //        PropNames.Add(prop.Name);
            //    }
            //}
            else if ((typeof(IDictionary)).IsAssignableFrom(TyThis))
            {
                IsDict = true;
            }
            else if ((typeof(NameValueCollection)).IsAssignableFrom(TyThis))
            {
                IsNameValueColl = true;
            }
            else //可能时 匿名对象，也可能时实体对象
            {
                Props = TyThis.GetProperties();
                PropNames = new List<string>();
                PropMapping = new Dictionary<string, PropertyInfo>();
                foreach (var prop in Props)
                {
                    PropMapping.Add(prop.Name, prop);
                    PropNames.Add(prop.Name);
                }
            }
        }

        //public static object GetValue(object obj, string propName, params PropertyInfo[] props)
        //{
        //    if (props != null)
        //    {
        //        return props.Where(t => t.Name == propName).FirstOrDefault()?.GetValue(obj);
        //    }
        //    return Props.Where(t => t.Name == propName).FirstOrDefault()?.GetValue(obj);
        //}

        public static Type TyThis { get; set; }

        public static bool IsValueType { get; set; }

        public static PropertyInfo[] Props { get; set; }


        public static Dictionary<string, PropertyInfo> PropMapping { get; set; } = new Dictionary<string, PropertyInfo>();


        public static List<string> PropNames { get; set; } = new List<string>();

        public static string Name { get; private set; }

        public static bool IsDict { get; private set; }

        public static bool IsNameValueColl { get; private set; }

        public static bool IsAnonymousType { get; private set; }

        public static bool IsArrayParameter { get; private set; }

        public static bool IsListParameter { get; private set; }

        public static void SetParam<P>(DbCommand cmd, object obj, DBType dataBaseType)
        {
            List<DbParameter> lstParas = new List<DbParameter>();
            var lstProp = TypeInfo<P>.Props;
            foreach (var prop in lstProp)
            {
                var parameter = cmd.CreateParameter();
                parameter.ParameterName = Global.ParameterCharMap[dataBaseType] + prop.Name;
                parameter.Value = prop.GetValue(obj, null);
                if (parameter.Value == null || parameter.Value == DBNull.Value)
                {
                    parameter.Value = DBNull.Value;
                }
                else
                {
                    Type tyValue = parameter.Value.GetType();
                    DbType dbType;
                    if (Global.TypeMap.TryGetValue(tyValue, out dbType))
                    {
                        parameter.DbType = dbType;
                    }
                    else
                    {
                        parameter.DbType = DbType.AnsiString;
                    }
                }
                cmd.Parameters.Add(parameter);
            }
        }

        public static void SetParam(DbCommand cmd, IDictionary dict, DBType dataBaseType)
        {
            List<DbParameter> lstParas = new List<DbParameter>();

            foreach (DictionaryEntry kv in dict)
            {
                var parameter = cmd.CreateParameter();
                parameter.ParameterName = Global.ParameterCharMap[dataBaseType] + kv.Key.ToString();
                parameter.Value = kv.Value;

                if (parameter.Value == null || parameter.Value == DBNull.Value)
                {
                    parameter.Value = DBNull.Value;
                }
                else
                {
                    Type tyValue = parameter.Value.GetType();
                    DbType dbType;
                    if (Global.TypeMap.TryGetValue(tyValue, out dbType))
                    {
                        parameter.DbType = dbType;
                    }
                    else
                    {
                        parameter.DbType = DbType.AnsiString;
                    }
                }
                cmd.Parameters.Add(parameter);
            }
        }

        public static void SetParam(DbCommand cmd, NameValueCollection nvc, DBType dataBaseType)
        {
            List<DbParameter> lstParas = new List<DbParameter>();

            foreach (string key in nvc.AllKeys)
            {
                var parameter = cmd.CreateParameter();
                parameter.ParameterName = Global.ParameterCharMap[dataBaseType] + key;
                parameter.Value = nvc[key];

                if (parameter.Value == null || parameter.Value == DBNull.Value)
                {
                    parameter.Value = DBNull.Value;
                }
                else
                {
                    parameter.DbType = DbType.AnsiString;
                }
                cmd.Parameters.Add(parameter);
            }
        }

    }
}
